#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define TRUE 1
#define FALSE 0

using namespace std;

void compile(vector<char>, ifstream&, ofstream&, int&);
void condition_compile(vector<char>, ofstream&, int&);
string find_name(vector<char>, unsigned long long, int, int&);
unsigned long long find_value(vector<char>, unsigned long long, int, int&);

int main(int argc, char* argv[])
{
    vector <char> alles;
    ifstream ifile;
    ofstream ofile;
    string filename;
    char temp;
    string blankstr;
    unsigned long long i(0);
    //Open all files
    if ( argc > 1 ) {
        ifile.open(argv[1]);
        if ( argc > 2) {ofile.open(argv[2]); }
        else {ofile.open("a.out"); }
    }
    else
    {
        cout << "No input file provided in command line. Enter filepath: " << endl;
        cin >> filename;
        if ( argc > 2) {ofile.open(argv[2]); }
        else {ofile.open("a.out"); }
    }
    bool readws = FALSE;
    while(!ifile.eof())
    {
        ifile >> temp;
        if (temp == '/')
        {
            do
            {
                ifile >> skipws >> temp;
            }while(temp != '/');
            ifile >> temp;
        }
        if (temp == '|')
        {
            do
            {
                alles.push_back(temp);
                ifile >> noskipws >> temp;
            }while(temp != '|' && !(ifile.eof()));
        }
        alles.push_back(temp);
    }
    alles.pop_back();
    for (int x = 0;x < alles.size(); x++) { cout << alles[x];} //View Entire loaded array...
    for (int i = 0; i < alles.size(); i++)
    {
        compile(alles,ifile,ofile, i);
    }
    return 0;
}
void compile(vector<char> alles, ifstream& ifile, ofstream& ofile, int& i)
{
    //Vars for manipulating within for loop
    unsigned long long stackvalue;
    int length = 0;
    char charvalue = '0';
    char boolvalue = '0';
    string* name_str, *blank_str;
    blank_str = new string;
    //End Vars for for loop
    switch(alles[i])//sentinel character
    {
        case '#': //declare a datatype
            switch(alles[i+1])//first letter of datatype
            {
                case 'i':
                    if(alles[i + 2] == 'n') {++i;}
                    ofile << "i '";
                    name_str = new string;
                    *name_str = find_name(alles,i,3,length);
                    i += length;
                    stackvalue = find_value(alles,i,3,length);
                    i += length;
                    ofile << stackvalue << "' " << '"' << *name_str << '"' << endl;
                    *name_str = *blank_str;
                    break;
                case 'c':
                    if(alles[i + 2] == 'h') {i += 2;}
                    if(alles[i + 3] == '[')
                    {
                        i+= 5;
                        //So, this will ofile << array syntax when Jt gets around to designing it
                    }
                    else
                    {
                        ofile << "c '";
                        name_str = new string;
                        *name_str = find_name(alles,i,3, length);
                        i += length;
                        while(alles[i] != '\n' && alles[i - 2] != '\'')
                        {
                            i++;
                        }
                        charvalue = alles[i - 1];
                        ofile << charvalue << "' \"" << *name_str << '"' << endl;
                        *name_str = *blank_str;
                    }
                    break;
                case 'b':
                    if(alles[i + 2] == 'o') {++i;}
                    if(alles[i + 3] == 'o') {++i;}
                    if(alles[i + 4] == 'l') {++i;}
                    name_str = new string;
                    *name_str = find_name(alles,i,4,length);
                    i += length;
                    boolvalue = alles[i + 4];
                    ofile << "b '" << boolvalue << "' \"" << *name_str << '"' << endl;
                    *name_str = *blank_str;
                    break;
                default:
                    break;
            } 
            break;
        case '|':
            switch(alles[i + 1])
            {
                case 'w':
                    if( (alles[i + 2] == 'h') && (alles[i + 3] == 'i') )
                    {
                        i += 7;
                        cout << alles[i];
                        ofile << "W_";
                        condition_compile(alles,ofile,i);
                    }
                    break;
                case 'f':
                    if( (alles[i + 2] == 'o') && (alles[i + 3] == 'r') && (alles[i + 4] == ' ') )
                        i+=5;//Yes, this is just test code, it wouldn't do a for loop well. While is easier
                        do
                        {
                            if(!(alles[i] == ' '))
                            cout << alles[i];
                            i++;
                        }while(!(alles[i] == '|'));
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }
}
void condition_compile(vector<char> alles, ofstream& ofile, int& i)
{
    while(!(alles[i] == '|'))
    {
        if(alles[i] == '"')
        {
            //Comparing a string to something
        }
        else if (alles[i] == ('(' - 1))
        {
            //Comparing a character to something
        }
        else if (isalpha(alles[i]))
        {
            cout << "name" << endl;
            //Comparing a name to something
            i++;
            ofile << '"';
            while(isalpha(alles[i]))
            {
                ofile << alles[i];
            }
            ofile << '"';
        }
        else if (alles[i] == '(')
        {
            cout << "Parenth. Will deal with later" << endl; i++;
        }
        else if( (alles[i] >= '<') && (alles[i] <= '>') )
        {
            while ( (alles[i] >= '<') && (alles[i] <= '>') )
            {
                ofile << alles[i];
                i++;
            }
        }
        else if (alles[i] == ' ')
        {
            i++;
        }
        else
        {
            cerr << "the compiler is wtfing. sorry" << endl;
            i++;
        }
    }
    ofile << "_";
}
string find_name(vector<char> alles, unsigned long long i, int x, int& l)
{
    queue<char> name_queue;
    string returnvalue;
    while((alles[i + x] >= 'A') && (alles[i + x] <= 'z'))
    {
        name_queue.push(alles[i + x]);
        i++;
    }
    if (name_queue.empty())
    {
        cerr << "attempt to declare variable without name";
    }
    while(name_queue.front())
    {
        returnvalue += name_queue.front();
        name_queue.pop();
    }
    return returnvalue;
}
unsigned long long find_value(vector<char> alles, unsigned long long i, int x, int& l)
{
    vector<int> num_vec;
    unsigned long long returnvalue = 0;
    while((alles[i + x] >= '0') && (alles[i + x] <= '9'))
    {
        num_vec.push_back(alles[i + x] - '0');
        i++;
    }
    if (num_vec.empty())
    {
        cerr << "attempt to declare variable without name" << endl;
    }
    for(int j = 0; j < num_vec.size(); j++)
    {
        returnvalue *= 10;
        returnvalue += num_vec[j];
    }
    if(((returnvalue / 10) * 10) == returnvalue)
    {
        return returnvalue;
    }
    else
    {
        return returnvalue;
    }
}
